/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
  
package org.erossi.common.exception;

import java.util.Calendar;
import java.util.Enumeration;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.erossi.common.util.AppCtx;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

/**
 * 'AppDumpExceptionResolver' class: classe pseudo-controller per la gestione delle 
 *   eccezioni generate dai controller veri e propri.
 *   
 * <p>
 *   La classe cattura lo stato dell'applicazione, creando un dump tesutale riportato dalla view e loggato.
 * </p>
 *
 * @author erossi
 * @version Oct 15, 2007
 */
public class AppDumpExceptionResolver extends SimpleMappingExceptionResolver implements ApplicationContextAware {
  
  private static final Log log = LogFactory.getLog(AppDumpExceptionResolver.class);
  
  private String appDumpAttributeName;
  
  private ApplicationContext apc;
  
  @Override
  @SuppressWarnings("unchecked")
  protected String buildLogMessage(Exception ex, HttpServletRequest request) {
    
    String debugString = new String();
    
    debugString += "\n### EXCEPTION ###\n";
    debugString += AppCtx.printDebug("Stack Trace", ex);
    
    debugString += "\n### APPLICATION CONTEXT ###\n";
    debugString += AppCtx.printDebug("Display Name", apc.getDisplayName());
    debugString += AppCtx.printDebug("Startup Date", apc.getStartupDate());
    String[] beanDefinitionNames = apc.getBeanDefinitionNames();
    for (int i = 0; i < beanDefinitionNames.length; i++) {
      debugString += AppCtx.printDebug(beanDefinitionNames[i], apc.getBean(beanDefinitionNames[i]));
    }
    
    debugString += "\n### REQUEST GENERAL INFO ###\n";
    debugString += AppCtx.printDebug("Timestamp", Calendar.getInstance());
    debugString += AppCtx.printDebug("Context Path", request.getContextPath());
    debugString += AppCtx.printDebug("Local Name", request.getLocalName());
    debugString += AppCtx.printDebug("Local Address", request.getLocalAddr());
    debugString += AppCtx.printDebug("Local Port", request.getLocalPort());
    debugString += AppCtx.printDebug("Remote Address", request.getRemoteAddr());
    debugString += AppCtx.printDebug("Remote Port", request.getRemotePort());
    debugString += AppCtx.printDebug("Local Address", request.getLocalAddr());
    debugString += AppCtx.printDebug("Remote User", request.getRemoteUser());
    debugString += AppCtx.printDebug("Request URI", request.getRequestURI());
    debugString += AppCtx.printDebug("Request URL", request.getRequestURL());
    
    debugString += "\n### REQUEST HEADERS ###\n";
    Enumeration<String> requestHeaders = request.getHeaderNames();
    while (requestHeaders.hasMoreElements()) {
      String headerName = requestHeaders.nextElement();
      debugString += AppCtx.printDebug(headerName, request.getHeader(headerName));
    }
    
    debugString += "\n### REQUEST ATTRIBUTES ###\n";
    Enumeration<String> requestAttributes = request.getAttributeNames();
    while (requestAttributes.hasMoreElements()) {
      String attributeName = requestAttributes.nextElement();
      debugString += AppCtx.printDebug(attributeName, request.getHeader(attributeName));
    }
    
    debugString += "\n### REQUEST PARAMETERS ###\n";
    Enumeration<String> requestParameters = request.getParameterNames();
    while (requestParameters.hasMoreElements()) {
      String parameterName = requestParameters.nextElement();
      debugString += AppCtx.printDebug(parameterName, request.getHeader(parameterName));
    }
    
    debugString += "\n### SERVER SYSTEM PROPERTIES ###\n";
    Properties sysProps = System.getProperties();
    Enumeration<String> sysPropsEnum = (Enumeration<String>) sysProps.propertyNames();
    while (sysPropsEnum.hasMoreElements()) {
      String key = (String) sysPropsEnum.nextElement();
      debugString += AppCtx.printDebug(key, sysProps.getProperty(key)); 
    }
    
    return debugString;
    
  }

  @Override
  protected void logException(Exception ex, HttpServletRequest request) {
    log.error(this.buildLogMessage(ex, request));
  }

  @Override
  protected ModelAndView getModelAndView(String viewName, Exception ex, HttpServletRequest request) {
    ModelAndView mv = super.getModelAndView(viewName, ex, request);
    mv.addObject(this.getAppDumpAttributeName(), this.buildLogMessage(ex, request));
    return mv;
  }

  /**
   * Imposta il valore dell'attributo 'applicationContext'
   * @param applicationContext il valore dell'attributo 'applicationContext'
   */
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.apc = applicationContext;
  }

  /**
   * Restituisce il valore dell'attributo 'appDumpAttributeName'
   * @return il valore dell'attributo appDumpAttributeName
   */
  public String getAppDumpAttributeName() {
    return this.appDumpAttributeName;
  }

  /**
   * Imposta il valore dell'attributo 'appDumpAttributeName'
   * @param appDumpAttributeName il valore dell'attributo 'appDumpAttributeName'
   */
  public void setAppDumpAttributeName(String appDumpAttributeName) {
    this.appDumpAttributeName = appDumpAttributeName;
  }

}

